/*
 * Copyright (c) 2015. For Intelligent Group.
 */

package com.intelligent.ispc.common.persistence;

import com.google.common.collect.Lists;
import com.intelligent.ispc.common.utils.Collections3;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.*;
import java.util.Collection;
import java.util.List;

/**
 * Created by Peter.Li on 2015/10/9.
 */
public class DynamicSpecifications {

    public static <T> Specification<T> bySearchFilter(final Collection<SearchFilter> filters, final Class<T> entityClazz) {
        return new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                if (Collections3.isNotEmpty(filters)) {

                    List<Predicate> predicates = Lists.newArrayList();
                    for (SearchFilter filter : filters) {
                        String[] names = StringUtils.split(filter.fieldName, ".");
                        Path expression = root.get(names[0]);
                        for (int i = 1; i < names.length; i++) {
                            expression = expression.get(names[i]);
                        }

                        // logic operator
                        switch (filter.operator) {
                            case EQ:
                                if ("false".equals(filter.value)) {
                                    predicates.add(builder.equal(expression, false));
                                } else if ("true".equals(filter.value)) {
                                    predicates.add(builder.equal(expression, true));
                                } else
                                    predicates.add(builder.equal(expression, filter.value));
                                break;
                            case LIKE:
                                if(!filter.value.equals("_")) {
                                    predicates.add(builder.like(expression, "%" + filter.value + "%"));
                                }
                                else  {
                                    predicates.add(builder.like(expression, "*" + filter.value + "*"));
                                }
                                break;
                            case GT:
                                predicates.add(builder.greaterThan(expression, (Comparable) filter.value));
                                break;
                            case LT:
                                predicates.add(builder.lessThan(expression, (Comparable) filter.value));
                                break;
                            case GTE:
                                predicates.add(builder.greaterThanOrEqualTo(expression, (Comparable) filter.value));
                                break;
                            case LTE:
                                predicates.add(builder.lessThanOrEqualTo(expression, (Comparable) filter.value));
                                break;
                        }
                    }

                    if (!predicates.isEmpty()) {
                        return builder.and(predicates.toArray(new Predicate[predicates.size()]));
                    }
                }

                return builder.conjunction();
            }
        };
    }

    public static <T> Predicate getPredicateBySearchFilter(final Collection<SearchFilter> filters, Root<T> root, CriteriaBuilder builder, final Class<T> entityClazz) {

        if (Collections3.isNotEmpty(filters)) {
            List<Predicate> predicates = Lists.newArrayList();
            for (SearchFilter filter : filters) {
                String[] names = StringUtils.split(filter.fieldName, ".");
                Path expression = root.get(names[0]);
                for (int i = 1; i < names.length; i++) {
                    expression = expression.get(names[i]);
                }

                // logic operator
                switch (filter.operator) {
                    case EQ:
                        predicates.add(builder.equal(expression, filter.value));
                        break;
                    case LIKE:
                        predicates.add(builder.like(expression, "%" + filter.value + "%"));
                        break;
                    case GT:
                        predicates.add(builder.greaterThan(expression, (Comparable) filter.value));
                        break;
                    case LT:
                        predicates.add(builder.lessThan(expression, (Comparable) filter.value));
                        break;
                    case GTE:
                        predicates.add(builder.greaterThanOrEqualTo(expression, (Comparable) filter.value));
                        break;
                    case LTE:
                        predicates.add(builder.lessThanOrEqualTo(expression, (Comparable) filter.value));
                        break;
                }
                if (!predicates.isEmpty()) {
                    return builder.and(predicates.toArray(new Predicate[predicates.size()]));
                }
            }
        }

        return builder.conjunction();
    }
}
